#pragma once

#include"Sock.hpp"
#include"Log.hpp"
#include"Epoll.hpp"
#include"Protocol.hpp"

#include<unistd.h>
#include<functional>
#include<iostream>
#include<vector>
#include<unordered_map>
#include<string>
#include<cassert>
using namespace bobo;

class TcpServer;  // 声明
class Connection; // 声明

using func_t = std::function<void(Connection*)>;
using callback_t = std::function<void(Connection*, std::string&)>;

class Connection
{
public:
    Connection(int sock = -1)
        :_sock(sock)
        ,_tsvr(nullptr)
    {}
    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    ~Connection()
    {}
public:
    int _sock; // 负责进行IO的文件描述符
    // 三个回调方法，表征的就是对_sock进行特定读写对应的方法
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    // 接收缓冲区&&发送缓冲区
    std::string _inbuffer; // 暂时没有办法处理二进制流，文本是可以的
    std::string _outbuffer;
    TcpServer* _tsvr; // 设置对TcpServer的回值指针
};
////////////////////////////////////////////////////////////////////////////
class TcpServer
{
    static const int gnum = 1024;
public:
    TcpServer(const uint16_t& port = 8080, int revsNum = gnum)
        :_port(port)
        ,_revsNum(revsNum)
    {
        // 1.创建listensock
        _listenSock = Sock::Socket();
        int opt = 1; setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof opt); // 取消TIME_WAIT
        Sock::Bind(_listenSock, _port);
        Sock::Listen(_listenSock);

        // 2.创建多路转接对象
        _poll.CreateEpoll();

        // 3.添加listensock到服务器中
        AddConnection(_listenSock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

        // 4.构建一个获取就绪事件的缓冲区
        _revs = new struct epoll_event[_revsNum];
    }
    // 专门针对任意sock进行添加TcpServe
    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        Sock::SetNonBlock(sock);
        // 除了_listensock,未来我们会存在大量的socket，每一个sock都必须被封装成为一个Connection
        // 当服务器中存在大量的Connection的时候，TcpServer就需要将所有的Connection要进行管理：先描述，在组织
        // 1. 构建conn对象，封装sock
        Connection* conn = new Connection(sock);
        conn->SetCallBack(recv_cb, send_cb, except_cb);
        conn->_tsvr = this;
        // 2. 添加sock到epoll中
        _poll.AddSockToEpoll(sock, EPOLLIN | EPOLLET); // 任何多路转接的服务器，一般默认只会打开对读取事件的关心，写入事件会按需进行打开！
        // 3. 还要将对应的Connection*对象指针添加到Connections映射表中！
        _connections.insert({sock, conn});
    }
    void Accepter(Connection* conn)
    {
        // 一定是listensock已经就绪了，此次读取会阻塞吗？不会
        // v1 -> v2 : 你怎么保证，底层只有一个连接就绪呢？
        while(true)
        {
            uint16_t clientPort = 0;
            std::string clientIp;
            int accept_errno = 0;
            // sock一定是常规的IO sock
            int sock = Sock::Accept(conn->_sock, &clientPort, &clientIp, &accept_errno);
            if(sock < 0)
            {
                if(accept_errno == EAGAIN || accept_errno == EWOULDBLOCK) break;
                else if(accept_errno == EINTR) continue; // 概率非常低
                else
                {
                    // accept失败
                    // logMessage(WARNING, "accept error, %d : %s\n", accept_errno, strerror(accept_errno));
                    break;
                }
            }
            else
            {
                // 将sock托管给TcpServer
                AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1)
                                  , std::bind(&TcpServer::Sender, this, std::placeholders::_1)
                                  , std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                logMessage(DEBUG, "accept client %s:%d success, add to epoll&&TcpServer success, sock: %d\n",\
                    clientIp.c_str(), clientPort, sock);
            }
        }
    }
    void Recver(Connection* conn)
    {
        bool err = false;
        // v1: 直接面向字节流，先进行常规读取
        while(true)
        {
            char buffer[1024];
            ssize_t n = recv(conn->_sock, buffer, sizeof(buffer) - 1, 0);
            if(n < 0)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK) break; //正常的
                else if(errno == EINTR) continue;
                else
                {
                    logMessage(ERROR, "recv error, %d : %s\n", errno, strerror(errno));
                    conn->_except_cb(conn);
                    err = true;
                    break;
                }
            }
            else if(n == 0)
            {
                logMessage(ERROR, "client[%d] quit, server close [%d]\n", conn->_sock, conn->_sock);
                conn->_except_cb(conn);
                err = true;
                break;
            }
            else
            {
                //读取成功
                buffer[n] = 0;
                conn->_inbuffer += buffer;
            }
        }
        // end while
        // logMessage(DEBUG, "conn->_inbuffer[sock: %d]: %s\n", conn->_sock, conn->_inbuffer.c_str());
        if(!err)
        {
            std::vector<std::string> messages;
            SplitMessage(conn->_inbuffer, &messages);
            // 我能保证走到这里，就是一个完整报文
            for(auto& msg : messages) _cb(conn, msg); //可以在这里将message封装成为task,然后push到任务队列，任务处理交给后端线程池
        }
    }
    void Sender(Connection* conn)
    {
        while(true)
        {
            ssize_t n = send(conn->_sock, conn->_outbuffer.c_str(), conn->_outbuffer.size(), 0);
            if(n > 0)
            {
                conn->_outbuffer.erase(0, n);
                if(conn->_outbuffer.empty()) break;
            }
            else
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else
                {
                    logMessage(ERROR, "send error, %d : %s\n", errno, strerror(errno));
                    conn->_except_cb(conn);
                    break;
                }
            }
        }
        if(conn->_outbuffer.empty()) EnableReadWrite(conn, true, false);
        else EnableReadWrite(conn, true, true);
    }
    void Excepter(Connection* conn)
    {
        if(!IsConnectionExists(conn->_sock)) return;
        // 1. 从epoll中移除
        bool res = _poll.DelSockFromEpoll(conn->_sock);
        assert(res); //要判断
        // 2. 从我们的unorder_map中移除
        _connections.erase(conn->_sock);
        // 3. close(sock);
        close(conn->_sock);
        // 4. delete conn;
        delete conn;

        logMessage(DEBUG, "Excepter 回收完毕，所有的异常情况\n");       
    }
    void EnableReadWrite(Connection* conn, bool readable, bool writeable)
    {
        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0));
        bool res = _poll.CtlEpoll(conn->_sock, events);
        assert(res);
    }
    void LoopOnce()
    {
        int n = _poll.WaitEpoll(_revs, _revsNum);
        for(int i = 0; i < n; ++i)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            // 将所有的异常，全部交给read或者write来统一处理！
            if(revents & EPOLLERR) revents |= (EPOLLIN | EPOLLOUT);
            if(revents & EPOLLHUP) revents |= (EPOLLIN | EPOLLOUT);

            if(revents & EPOLLIN)
            {
                if(IsConnectionExists(sock) && _connections[sock]->_recv_cb != nullptr)
                    _connections[sock]->_recv_cb(_connections[sock]);
            }
            if(revents & EPOLLOUT)
            {
                if(IsConnectionExists(sock) && _connections[sock]->_send_cb != nullptr)
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }
    // 根据就绪的事件，进行特定事件的派发
    void Dispatcher(callback_t cb)
    {
        _cb = cb;
        while(true)
        {
            LoopOnce();
        }
    }
    bool IsConnectionExists(int sock)
    {
        auto iter = _connections.find(sock);
        if(iter == _connections.end()) return false;
        return true;
    }
    ~TcpServer()
    {
        if(_listenSock >= 0) close(_listenSock);
        if(_revs) delete[] _revs;
    }
private:
    int _listenSock;
    uint16_t _port;
    Epoll _poll;
    std::unordered_map<int, Connection*> _connections;
    struct epoll_event* _revs;
    int _revsNum;

    callback_t _cb;
};